package server;

import connect.ConnectionData;
import connect.Picture;

import java.io.*;
import java.net.*;
import java.util.*;

public class ConnectedClient {
    private ConnectionKeeper ck;
    public String nick;
    public Date connectedTime;
    public String ipNumber;
    public int portNumber;
    public boolean verifyedBoolean = false;
    public int verifyedCount = 0;
    public String tmpNick = "";
    private ServerMsgSender msgSend;
    private ServerMsgListener msgList;
    private Socket sock;
    public boolean printMsg = false;

    public ConnectedClient(Socket sock, ConnectionKeeper ck) {
        this.ck = ck;
        ipNumber = sock.getInetAddress().getHostAddress();
        portNumber = sock.getPort();
        this.sock = sock;
        msgSend = new ServerMsgSender(this.sock, this);
        msgList = new ServerMsgListener(this.sock, this);
        nick = "" + portNumber;
    }

    public ConnectionKeeper getConnectionKeeper() {
        return ck;
    }

    public String getNick() {
        return nick;
    }

    public void sendMessage(String str) {
        msgSend.addMessage(new ConnectionData(str));
    }
    public void sendImage(ConnectionData con) {
        msgSend.addMessage(con);
    }

    public void sendTo(String user, ConnectionData con) {
        ck.sendTo(this, user, con);
    }

    public void broadcastMessage(ConnectionData con) {
        ck.broadcast(con);
    }

    public void dropClient() {
        msgList.closeConnection();
        msgSend.closeConnection();
        ck.remove(this);
    }

    public void runCommand(ConnectionData con) {
        ck.runCommand(this, con);
    }

    private boolean isSpam(String str) {
        return false;
    }

    public static void main(String arg[]) {
        MainServer ms = new MainServer(1984);
    }

    public void whoAmI() {
        String str = "<br>Connected Port: " + portNumber + "<br>" +
                "Nick: " + nick + "<br>";
        sendMessage(str);
    }
}

class ServerMsgSender extends Thread {
    private Socket sock;
    private LinkedList<ConnectionData> msgList;
    private ConnectedClient cc;
    private boolean running = true;

    public ServerMsgSender(Socket sock, ConnectedClient cc) {
        this.sock = sock;
        this.cc = cc;
        collectInfo();
        msgList = new LinkedList();
        start();
    }

    public synchronized void addMessage(ConnectionData con) {
//        if (cc.printMsg) System.out.println("MsgSender.addMessage: " + str);
        msgList.addLast(con);
    }

    private void collectInfo() {
    }

    public void run() {
        ObjectOutputStream os = null;
        try {
            os = new ObjectOutputStream(sock.getOutputStream());
            while (running) {
                while (msgList.size() > 0) {
                    Object con = (Object) (msgList.removeFirst());
                    os.writeObject(con);
                    os.flush();
//                    if (cc.printMsg) System.out.println("MsgSender.run: Sending: " + toSend);
                    sleep(10);
                }
                sleep(10);
            }
//            DataOutputStream dataOut = new DataOutputStream(sock.getOutputStream());
//            while (running) {
//                while (msgList.size() > 0) {
//                    String toSend = (String) (msgList.removeFirst());
//                    dataOut.writeBytes("" + toSend + MainServer.MSGENDCHAR);
//                    if (cc.printMsg) System.out.println("MsgSender.run: Sending: " + toSend);
//                    sleep(10);
//                }
//                sleep(10);
//            }
        } catch (Exception e) {
            String msg = e.getMessage();
            if (msg.startsWith(MainServer.DISCONNECTED) ||
                    msg.startsWith(MainServer.DISCONNECTED_CLIENT)) {
                System.out.println("MsgSender.run Client disconnected nick: " + cc.nick);
                cc.dropClient();
            } else {
                System.out.println("MsgSender.run: Msg: " + msg);
                e.printStackTrace();
                cc.dropClient();
            }
        }
        finally{
            try {
                os.close();
            } catch (IOException e) {
            }
        }
    }

    public void closeConnection() {
        running = false;
    }
}

class ServerMsgListener extends Thread {
    private LinkedList msgList;
    private Socket sock;
    private ConnectedClient cc;
    private boolean running = true;

    public ServerMsgListener(Socket s, ConnectedClient cc) {
        msgList = new LinkedList();
        sock = s;
        this.cc = cc;
        start();
    }

    public void closeConnection() {
        running = false;
    }

    public void run() {
        ObjectInputStream is = null;
        try {
            is = new ObjectInputStream(new BufferedInputStream(sock.getInputStream()));
            while (running) {
//                int c;
                boolean didRun = false;
                boolean isCommand = false;
                Object obj = is.readObject();
                ConnectionData con = (ConnectionData) obj;
                if (!didRun) didRun = true;
                    if (con.getFunction()) { isCommand = true; }
                    if (cc.verifyedCount > 0 && !cc.verifyedBoolean && !isCommand) {
                        cc.verifyedCount--;
                        if (cc.verifyedCount == 1) {
                            cc.sendMessage("You have failed to verify your nick");
                            cc.nick = "" + cc.portNumber;
                            cc.sendMessage("Your nick is " + cc.nick);
                        } else {
                            cc.sendMessage("type: \"/verify &lt;password&gt\" to verify your nick");
                        }
                    }
                    if (didRun) {
                        if (!isCommand) {
                            String str=con.getToken();
                            con.setToken(cc.nick+": "+str);
                            cc.broadcastMessage(con);
                        }
                        else cc.runCommand(con);
                    }

            }
        } catch (SocketException se) {
            if (se.getMessage().startsWith("Connection reset"))
                cc.dropClient();
        } catch (Exception e) {
            e.printStackTrace();
            cc.dropClient();
        }
        finally {
            try {
                is.close();
            } catch (IOException e) {

            }
        }
    }
}
